package org.meetunexpectedly.service.user.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.meetunexpectedly.constant.RedisConstant;
import org.meetunexpectedly.entity.user.Follow;
import org.meetunexpectedly.entity.vo.BasePage;
import org.meetunexpectedly.exception.BaseException;
import org.meetunexpectedly.mapper.user.FollowMapper;
import org.meetunexpectedly.service.user.FeedService;
import org.meetunexpectedly.service.user.FollowService;
import org.meetunexpectedly.service.video.VideoService;
import org.meetunexpectedly.util.RedisCacheUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 关注服务实现类
 * @Author: pupil
 * @Date: 2024/08/11 下午 9:12
 */
@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements FollowService {

    @Autowired
    private RedisCacheUtil redisCacheUtil;

    @Autowired
    private FeedService feedService;

    @Autowired
    @Lazy
    private VideoService videoService;

    @Override
    public int getFollowsCount(Long userId) {
        int count = this.count(new LambdaQueryWrapper<Follow>().eq(Follow::getUserId, userId));
        return count;
    }

    @Override
    public int getFansCount(Long userId) {
        int count = this.count(new LambdaQueryWrapper<Follow>().eq(Follow::getFollowId, userId));
        return count;
    }

    @Override
    public Collection<Long> getFans(BasePage basePage, Long userId) {
        // 判断是否有分页基础信息
        if (basePage == null) {
            // 从redis缓存中获取粉丝列表
            Set<Object> set = redisCacheUtil.zGet(RedisConstant.USER_FANS + userId);
            // redis缓存中的粉丝列表为空，则返回空集合
            if (ObjectUtils.isEmpty(set)) {
                return Collections.EMPTY_SET;
            }
            // 字符串转换为Long类型
            return set.stream().map(o -> Long.valueOf(o.toString())).collect(Collectors.toList());
        }

        Set<ZSetOperations.TypedTuple<Object>> set = redisCacheUtil.zSetGetByPage(RedisConstant.USER_FANS + userId, basePage.getPage(), basePage.getLimit());
        // redis缓存中的粉丝列表为空，则从数据库中获取，数据库也为空则返回空集合
        if (ObjectUtils.isEmpty(set)) {
            // 从数据库中获取粉丝列表
            List<Follow> follows = page(basePage.page(), new LambdaQueryWrapper<Follow>().eq(Follow::getFollowId, userId).orderByDesc(Follow::getGmtCreated)).getRecords();
            if (ObjectUtils.isEmpty(follows)) {
                return Collections.EMPTY_LIST;
            }
            // 将数据存储到redis中（优化）
            for (Follow follow : follows) {
                // 粉丝id
                Long fansId = follow.getUserId();
                // 关注时间
                Date date = follow.getGmtCreated();
                // 对方关注列表添加
                redisCacheUtil.addZSet(RedisConstant.USER_FOLLOWS + fansId, userId, date.getTime());
                // 自己粉丝列表添加
                redisCacheUtil.addZSet(RedisConstant.USER_FANS + userId, fansId, date.getTime());
            }

            return follows.stream().map(Follow::getFollowId).collect(Collectors.toList());
        }

        return set.stream().map(o -> Long.valueOf(o.getValue().toString())).collect(Collectors.toList());
    }

    @Override
    public Collection<Long> getFollows(BasePage basePage, Long userId) {
        // 判断是否有分页基础信息
        if (basePage == null) {
            // 从redis缓存中获取关注列表
            Set<Object> set = redisCacheUtil.zGet(RedisConstant.USER_FOLLOWS + userId);
            // redis缓存中的关注列表为空，则返回空集合
            if (ObjectUtils.isEmpty(set)) {
                return Collections.EMPTY_SET;
            }
            // 字符串转换为Long类型
            return set.stream().map(o -> Long.valueOf(o.toString())).collect(Collectors.toList());
        }

        Set<ZSetOperations.TypedTuple<Object>> set = redisCacheUtil.zSetGetByPage(RedisConstant.USER_FOLLOWS + userId, basePage.getPage(), basePage.getLimit());
        // redis缓存中的关注列表为空，则从数据库中获取，数据库也为空则返回空集合
        if (ObjectUtils.isEmpty(set)) {
            // 从数据库中获取关注列表
            List<Follow> follows = page(basePage.page(), new LambdaQueryWrapper<Follow>().eq(Follow::getUserId, userId).orderByDesc(Follow::getGmtCreated)).getRecords();
            if (ObjectUtils.isEmpty(follows)) {
                return Collections.EMPTY_LIST;
            }
            // 将数据存储到redis中(优化)
            for (Follow follow : follows) {
                // 关注者id
                Long followsUserId = follow.getFollowId();
                // 关注时间
                Date date = follow.getGmtCreated();
                // 自己关注列表添加
                redisCacheUtil.addZSet(RedisConstant.USER_FOLLOWS + userId, followsUserId, date.getTime());
                // 对方粉丝列表添加
                redisCacheUtil.addZSet(RedisConstant.USER_FANS + followsUserId, userId, date.getTime());
            }

            return follows.stream().map(Follow::getFollowId).collect(Collectors.toList());
        }

        return set.stream().map(o -> Long.valueOf(o.getValue().toString())).collect(Collectors.toList());
    }

    @Override
    public Boolean follows(Long userId, Long followsUserId) {
        if (userId.equals(followsUserId)) {
            throw new BaseException("不能关注自己");
        }

        // 直接保存（唯一索引），存在则保存失败直接删除
        Follow follow = new Follow();
        follow.setUserId(userId);
        follow.setFollowId(followsUserId);

        try {
            this.save(follow);
            Date date = new Date();
            // 自己关注列表添加
            redisCacheUtil.addZSet(RedisConstant.USER_FOLLOWS + userId, followsUserId, date.getTime());
            // 对方粉丝列表添加
            redisCacheUtil.addZSet(RedisConstant.USER_FANS + followsUserId, userId, date.getTime());
        } catch (Exception e) {
            // 删除
            remove(new LambdaQueryWrapper<Follow>().eq(Follow::getFollowId, followsUserId).eq(Follow::getUserId, userId));

            // 获取关注人的视频
            List<Long> videoIds = (List<Long>) videoService.listVideoIdByUserId(followsUserId);
            // 删除用户收件箱的视频
            feedService.deleteInBoxFeed(userId, videoIds);

            // 自己关注列表中删除
            redisCacheUtil.removeZSet(RedisConstant.USER_FOLLOWS + userId, followsUserId);
            // 对方粉丝列表中删除
            redisCacheUtil.removeZSet(RedisConstant.USER_FANS + followsUserId, userId);
            return false;
        }

        return true;
    }

    @Override
    public Boolean isFollows(Long followId, Long userId) {
        if (userId == null) return false;
        // 关注数为1则已关注   关注数为0则未关注
        return this.count(new LambdaQueryWrapper<Follow>().eq(Follow::getFollowId, followId).eq(Follow::getUserId, userId)) == 1;
    }

}
